package com.louis.pluginproject;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;

import dalvik.system.DexClassLoader;

public class PluginManager {
    private static PluginManager pluginManager;
    private static final String TAG = "PluginManager";

    private Context context;

    public static PluginManager getInstance(Context context) {
        if (pluginManager == null) {
            synchronized (PluginManager.class) {
                if (pluginManager == null) {
                    pluginManager = new PluginManager(context);
                }
            }
        }
        return pluginManager;
    }

    public PluginManager(Context context) {
        this.context = context;
    }

    private DexClassLoader dexClassLoader;
    private Resources resources;

    public void loadPlugin() {
        try {
            File file = new File(Environment.getExternalStorageDirectory() + File.separator + "p.apk");
            if (!file.exists()) {
                Log.d(TAG, "loadPlugin: 插件包不存在");
                return;
            } else {
                Log.d(TAG, "loadPlugin: 插件包存在");
            } 

            String pluginPath = file.getAbsolutePath();

            //加载插件里面的class
            //缓存目录 dexClassLoader /data/data/当前应用的包名/pDir
            File fileDir = context.getDir("pDir", Context.MODE_PRIVATE);
            //Activity class
            dexClassLoader = new DexClassLoader(pluginPath, fileDir.getAbsolutePath(), null, context.getClassLoader());

            //加载插件里面的layout
            //加载资源
            AssetManager assetManager = AssetManager.class.newInstance();
            //执行此方法，把插件包的路径添加进去
            Method addAssetPathMethod = assetManager.getClass().getMethod("addAssetPath", String.class);
//            addAssetPathMethod.setAccessible(true);
            addAssetPathMethod.invoke(assetManager, pluginPath);

            //宿主的资源配置信息
            Resources r = context.getResources();

            //特殊的Resources，加载插件里面的资源的Resources
            this.resources = new Resources(assetManager, r.getDisplayMetrics(), r.getConfiguration());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public DexClassLoader getDexClassLoader() {
        return dexClassLoader;
    }

    public Resources getResources() {
        return resources;
    }

    //反射系统源码，来解析apk文件里面的所有信息
    public void parseApkAction(){
        try {
            //插件包路径
            File file = new File(Environment.getExternalStorageDirectory() + File.separator + "p.apk");
            if (!file.exists()) {
                Log.d(TAG, "loadPlugin: 插件包不存在");
                return;
            } else {
                Log.d(TAG, "loadPlugin: 插件包存在");
            }

            String pluginPath = file.getAbsolutePath();

            //实例化PackageParse对象
            Class<?> mPackageParseClass = Class.forName("android.content.pm.PackageParser");
            Object mPackageParser = mPackageParseClass.newInstance();

            //1 执行此public Package parsePackage(File packageFile, int flags)，为了拿到Package
            Method parsePackageMethod = mPackageParseClass.getMethod("parsePackage", File.class, int.class);
            Object mPackage = parsePackageMethod.invoke(mPackageParser, file, PackageManager.GET_ACTIVITIES);

            //继续分析Package
            //得到receivers
            Field receiversField = mPackage.getClass().getDeclaredField("receivers");
            //receivers本质就是ArrayList集合
            Object receivers = receiversField.get(mPackage);

            ArrayList arrayList = (ArrayList) receivers;
            for (Object mActivity : arrayList) {
                //获取<intent-filter> intents == Intent-Filter
                //通过反射拿到intents
                Class<?> componentClass = Class.forName("android.content.pm.PackageParser$Component");
                Field intentsField = componentClass.getDeclaredField("intents");
                ArrayList<IntentFilter> intents = (ArrayList) intentsField.get(mActivity);

                Class<?> packageUserStateClass = Class.forName("android.content.pm.PackageUserState");
                Class<?> userHandleClass = Class.forName("android.os.UserHandle");
                int userId = (int) userHandleClass.getMethod("getCallingUserId").invoke(null);
                //拿到android：name
                // activityInfo.name == android:name
                // 执行此方法拿到ActivityInfo public static final ActivityInfo generateActivityInfo(Activity a, int flags,PackageUserState state, int userId)
                Method generateActivityInfoMethod = mPackageParseClass.getMethod("generateActivityInfo", mActivity.getClass(), int.class, packageUserStateClass, int.class);
                ActivityInfo mActivityInfo = (ActivityInfo) generateActivityInfoMethod.invoke(null, mActivity, 0, packageUserStateClass.newInstance(),userId);
                String receiverClassName = mActivityInfo.name;
                Class mStaticReceiverClass = getDexClassLoader().loadClass(receiverClassName);
                BroadcastReceiver broadcastReceiver = (BroadcastReceiver) mStaticReceiverClass.newInstance();

                for (IntentFilter intentFilter : intents) {
                    //注册广播
                    context.registerReceiver(broadcastReceiver,intentFilter);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
